package com.amiu.shiro;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;


/**
 * 自定义shiro filter,我们可以继承很多Filter来重写需要的方法，
 * 所有filter请产看源码org.apache.shiro.web.filter，这里有
 * 很多filter不同功能的filter可供选择
 * 可以在org.apache.shiro.web.filter.mgt.DefaultFilter中查看
 * 指定filter的字符串对应的具体类
 * @author amiu
 * @version createtime：2017-9-15 下午7:58:29
 */
public class AnyRolesFilter extends AccessControlFilter {

    private String unauthorizedUrl = "/unauthorized.jsp";
    private String loginUrl = "/login.jsp";

  //是否允许当前用户访问，mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    	/**
    	 * 这个方法原本的实现是需要匹配roles中所有的角色才通过：
    	 * 比如roles["管理员","测试"]
    	 * 那么当前用户必须匹配这两个角色user["管理员","测试"]，才能访问
    	 * 但是如果按照我们日常的逻辑设计来说，我拥有了“管理员”权限，那么
    	 * 我肯定拥有“测试”账户的所有权限。
    	 * 这里就可以让拥只有“管理员”权限的用户访问user["管理员"]
    	 */
    	
    	Subject user = getSubject(request, response);
        String[] roles = (String[])mappedValue;//获取我们设置能访问的角色
        if(roles == null || roles.length == 0) {
        	//如果没有设置角色参数，说明任何角色都能访问，默认成功
            return true;
        }
        for(String role : roles) {//遍历["管理员","测试"]
            if(user.hasRole(role)) {
            	//当user拥有["管理员"]即可访问，["测试"]权限是不必要的
            	/**
            	 * 当然如果roles["管理员","测试"]，而user["测试"]，
            	 * 这时我们就要做特殊处理，不能这么处理了，
            	 * 毕竟我们不能让只拥有["测试"]权限的user拥有更大的权限["管理员"]
            	 */
                return true;
            }
        }
        return false;//跳到onAccessDenied处理
    }
    /**
     * 拒绝用户访问的时候需要做什么,如果需要特殊化处理在这里面写
     * 如果返回true表示需要继续默认处理；如果返回false表示该拦截器实例已经处理了，
     * 将直接返回即可
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (subject.getPrincipal() == null) {//表示没有登录，重定向到登录页面
            saveRequest(request);
            WebUtils.issueRedirect(request, response, loginUrl);
        } else {
            if (StringUtils.hasText(unauthorizedUrl)) {//如果有未授权页面跳转过去
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            } else {//否则返回401未授权状态码
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
            }
        }
        return false;
    }
}
